package com.xhtt.modules.inspection.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhtt.common.exception.RRException;
import com.xhtt.common.exception.RRExceptionEnum;
import com.xhtt.common.utils.ExportExcel;
import com.xhtt.common.utils.JsonUtil;
import com.xhtt.common.utils.PageUtils;
import com.xhtt.common.utils.Query;
import com.xhtt.modules.inspection.dao.InsLabelMapper;
import com.xhtt.modules.inspection.entity.InsLabel;
import com.xhtt.modules.inspection.service.IInsLabelService;
import com.xhtt.modules.inspection.service.IInsPointLabelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * <p>
 * 巡检标签 服务实现类
 * </p>
 *
 * @author xj
 * @since 2019-01-18
 */
@Service
@Slf4j
public class InsLabelServiceImpl extends ServiceImpl<InsLabelMapper, InsLabel> implements IInsLabelService {

    @Autowired
    private IInsPointLabelService insPointLabelService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Page<InsLabel> page = new Query<InsLabel>(params).getPage();
        IPage<InsLabel> iPage = baseMapper.selectPage(page, new LambdaQueryWrapper<InsLabel>()
                .like(Optional.ofNullable(params.get("code")).isPresent(), InsLabel::getCode, (String) params.get("code"))
                .like(Optional.ofNullable(params.get("name")).isPresent(), InsLabel::getName, (String) params.get("name"))
                .orderByDesc(InsLabel::getUpdateTime));

        // 添加绑定检测点名称
        List<InsLabel> labelList = iPage.getRecords();
        if (CollectionUtils.isNotEmpty(labelList)) {
            for (InsLabel label : labelList) {
                List<String> pointNameList = insPointLabelService.getDeviceNamesByLabelId(label.getId());
                if (CollectionUtils.isNotEmpty(pointNameList)) {
                    // 直接用逗号隔开返回给页面
                    label.setDeviceName(pointNameList.stream().collect(Collectors.joining(",")));
                }
            }
        }
        return new PageUtils(iPage);
    }

    @Override
    public void add(InsLabel insLabel) {
        this.valid(insLabel);
        this.save(insLabel);
    }

    private void valid(InsLabel insLabel) {
        // 判断标签编码或者标签名称是否已存在
        int codeExist = this.count(new LambdaQueryWrapper<InsLabel>().eq(InsLabel::getCode, insLabel.getCode()));
        int nameExist = this.count(new LambdaQueryWrapper<InsLabel>().eq(InsLabel::getName, insLabel.getName()));
        StringBuilder stringBuilder = new StringBuilder();
        if (codeExist > 0) {
            stringBuilder.append(RRExceptionEnum.LABEL_CODE_EXIST.getMsg());
        }
        if (nameExist > 0) {
            if (StringUtils.isNotEmpty(stringBuilder.toString())) {
                stringBuilder.append(",");
            }
            stringBuilder.append(RRExceptionEnum.LABEL_NAME_EXIST.getMsg());
        }
        if (StringUtils.isNotEmpty(stringBuilder.toString())) {
            throw new RRException(stringBuilder.toString());
        }
    }

    @Override
    public void upload(Map<Long, Map<Integer, String>> params) {
        Long headerRowNum = 2L;

        // 初始化下标（用于判断头部字段是否存在,以及对应关系）
        int labelCodeIndex = -1;
        int labelNameIndex = -1;
        int describeIndex = -1;
        int posDescribeIndex = -1;

        // 标签编码为空行的下标集合
        Set<Integer> codeEmptyIndex = new HashSet<>();
        // 标签名称为空行的下标集合
        Set<Integer> nameEmptyIndex = new HashSet<>();
        // 标签编码重复行数下标集合
        Set<Integer> codeRepeatIndex = new HashSet<>();
        // 标签名称重复行数下标集合
        Set<Integer> nameRepeatIndex = new HashSet<>();
        // 系统异常
        Set<Integer> sysErrorIndex = new HashSet<>();

        // 获取头部一行数数据
        Map<Integer, String> header = params.get(headerRowNum);
        for (int headerIndex : header.keySet()) {
            String f = header.get(headerIndex).trim();
            switch (f) {
                case InsLabel.LABEL_CODE:
                    labelCodeIndex = headerIndex;
                    break;
                case InsLabel.LABEL_NAME:
                    labelNameIndex = headerIndex;
                    break;
                case InsLabel.LABEL_DESCRIBE:
                    describeIndex = headerIndex;
                    break;
                case InsLabel.LABEL_POS_DESCRIBE:
                    posDescribeIndex = headerIndex;
                    break;
            }
        }
        if (labelCodeIndex == -1 || labelNameIndex == -1 || describeIndex == -1 || posDescribeIndex == -1) {
            throw new RRException(RRExceptionEnum.EXCEL_HEADER_ERROR);
        }
        params.remove(headerRowNum);

        // 遍历并保存
        int finalLabelCodeIndex = labelCodeIndex;
        int finalLabelNameIndex = labelNameIndex;
        int finalDescribeIndex = describeIndex;
        int finalPosDescribeIndex = posDescribeIndex;
        params.forEach((k, v) -> {
            //  判断是否有错误
            AtomicBoolean hasError = new AtomicBoolean(false);
            InsLabel insLabel = new InsLabel();
            Map<Integer, String> row = params.get(k);
            row.forEach((rk, rv) -> {
                String rowItem = row.get(rk);
                try {
                    if (rk == finalLabelCodeIndex) {
                        if (StringUtils.isEmpty(rowItem)) {
                            codeEmptyIndex.add(k.intValue());
                            hasError.set(true);
                        } else {
                            insLabel.setCode(rowItem);
                        }
                    }
                } catch (Exception e) {
                    sysErrorIndex.add(k.intValue());
                }

                try {
                    if (rk == finalLabelNameIndex) {
                        if (StringUtils.isEmpty(rowItem)) {
                            nameEmptyIndex.add(k.intValue());
                            hasError.set(true);
                        } else {
                            insLabel.setName(rowItem);
                        }
                    }
                } catch (Exception e) {
                    sysErrorIndex.add(k.intValue());
                }

                try {
                    if (rk == finalDescribeIndex) insLabel.setDescript(rowItem);
                } catch (Exception e) {
                    sysErrorIndex.add(k.intValue());
                }

                try {
                    if (rk == finalPosDescribeIndex) insLabel.setPosDescript(rowItem);
                } catch (Exception e) {
                    sysErrorIndex.add(k.intValue());
                }

            });
            try {
                if (!hasError.get()) {
                    this.add(insLabel);
                }
            } catch (Exception ex) {
                hasError.set(true);
                if (ex.getMessage().trim().equals(RRExceptionEnum.LABEL_CODE_EXIST.getMsg())) {
                    codeRepeatIndex.add(k.intValue());
                } else if (ex.getMessage().trim().equals(RRExceptionEnum.LABEL_NAME_EXIST.getMsg())) {
                    nameRepeatIndex.add(k.intValue());
                } else {
                    // 两个都重复
                    codeRepeatIndex.add(k.intValue());
                    nameRepeatIndex.add(k.intValue());
                }
            }
        });

        StringBuilder stringBuilder = new StringBuilder();
        if (CollectionUtils.isNotEmpty(codeEmptyIndex)) {
            stringBuilder.append(formatUploadEx("第", codeEmptyIndex, "行标签编码为空"));
        }
        if (CollectionUtils.isNotEmpty(nameEmptyIndex)) {
            stringBuilder.append(formatUploadEx("第", nameEmptyIndex, "行标签名称为空"));
        }
        if (CollectionUtils.isNotEmpty(codeRepeatIndex)) {
            stringBuilder.append(formatUploadEx("第", codeRepeatIndex, "行标签编码重复"));
        }
        if (CollectionUtils.isNotEmpty(nameRepeatIndex)) {
            stringBuilder.append(formatUploadEx("第", nameRepeatIndex, "行标签名称重复"));
        }
        if (StringUtils.isNotEmpty(stringBuilder.toString())) {
            throw new RRException(stringBuilder.toString());
        }

        log.warn(formatUploadEx("第", sysErrorIndex, "行发生系统异常").toString());
    }

    @Override
    public void exportExcel(HttpServletResponse response, Map<String, Object> params) {
        ExportExcel exportExcel = new ExportExcel();

        params.put("limit", "65000");

        PageUtils pageUtils = queryPage(params);
        List list = pageUtils.getList();
        String fileName = "标签数据";
        String sheetName = "sheet1";
        String[] headers = {"标签名称", "标签描述", "标签编码", "具体位置描述", "绑定检点"};
        String[] columns = {"name", "descript", "code", "posDescript", "deviceName"};
        try {
            exportExcel.exportExcel(fileName, sheetName, headers, columns, list, response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RRException(RRExceptionEnum.EXPORT_FAIL);
        }
    }

    @Override
    public StringBuilder formatUploadEx(String begin, Set<?> indexSet, String tip) {
        StringBuilder stringBuilder = new StringBuilder();
        String indexRealStr = convert(indexSet);
        String indexStr = convert(indexSet.stream().limit(10).collect(Collectors.toSet()));
        if (indexSet.size() > 10) {
            indexStr = indexStr + " ... ";
        }
        stringBuilder.append("<span style=\"width: 300px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;\" title=\"").append(indexRealStr).append("\">").append(begin).append(indexStr).append(tip).append("</span><br/>");
        return stringBuilder;
    }

    private String convert(Set<?> set) {
        return set.stream().map(e -> {
            if (e instanceof String) return (String) e;
            else if (e instanceof Integer) return Integer.toString((Integer) e);
            else log.error("set can not be converted: {}", JsonUtil.toJson(set)); return "";
        }).collect(Collectors.joining("、"));
    }
}
